home *** CD-ROM | disk | FTP | other *** search
- {*******************************************************
- TNodes [Nodes unit]
-
- This unit contains the a number of string manipulation routines
- most of which came from Niel Rubenking's Turbo Pascal 6.0
- Techniques and Utilities. Probably the best book on Pascal
- programming I have.
-
- Other routines I wrote myself and one or two come from sources
- I have long since forgotten. I apologize to Niel Rubenking and
- anyone else who may find a routine they wrote in this library
- for not indicating which is which. However, I just can't
- remember. I do know the they were all in the public domain
- though so I figure its alright this way.
-
- Paul Warren
- HomeGrown Software Development
- (c) 1995 Langley British Columbia.
- (604) 530-9097
- e-mail: hg_soft@uniserve.com
- Home page: http://haven.uniserve.com/~hg_soft
-
- ********************************************************}
-
- unit StrLib;
-
- interface
-
- uses SysUtils, Graphics;
-
- type
- Justification = (jLeft, jRight, jCenter);
-
- function UpperCase(S : string) : string;
- function Dupe(C : Char; Len : Byte) : string;
- function ADupe(C : Char; Len : Byte) : string;
- function Pad(S : string; C : Char; Len : Byte) : string;
- function APad(S : string; C : Char; Len : Byte) : string;
- function LeftPad(S : string; C : Char; Len : Byte) : string;
- function ALeftPad(S : string; C : Char; Len : Byte) : string;
- function Chop(S : string; len: Byte): string;
- procedure RChop(var S: string; len: Byte);
- function AChop(S : string; len: Byte): string;
- function LeftChop(S : string; len: Byte): string;
- function LeftChopBy(S : string; len: Byte): string;
- procedure LChop(var S: string; len: Byte);
- procedure LChopBy(var S: string; len: Byte);
- function ALeftChop(S : string; len: Byte): string;
- procedure Trim(var S : string; C : Char);
- procedure TrimTo(var S : string; C : Char);
- procedure TrimLead(var S : string; C : Char);
- function LRTrim(S: string): string;
- function NumLong(L: LongInt): string;
- function RealToStr(R: real; NumDec: byte): string;
- function StrTOReal(var code: integer; S: string): real;
- procedure Replace(NewString, OldString: string; var MainString: string);
- procedure InsertAfter(NewString, AnchorString: string;
- var MainString: string; Spacer: byte);
- procedure CopyInto(const InStr: string; Column: Byte; var OutStr: string);
- function SubStr(S: string; BegChar, EndChar: char): string;
- function JustifyStr(var S: string; L: byte; Just: Justification): string;
- function StrToMask ( S : string; Mask : string ) : string;
- function StripMask ( S : string ) : string;
- function MinimizeName(const Filename: TFileName; Canvas: TCanvas;
- MaxLen: Integer): TFileName;
-
- implementation
-
- function UpperCase(S: string): string;
- var P: Byte;
- begin
- for P := 1 to length(S) do
- S[P] := UpCase(S[P]);
- UpperCase := S;
- end;
-
- function Dupe(C: Char; Len: Byte): string;
- var Temp: string;
- begin
- FillChar(Temp[1], Len, C);
- Temp[0] := Char(Len);
- Dupe := Temp;
- end;
-
- function ADupe(C : Char; Len : Byte): string; Assembler;
- ASM
- LES DI, @Result
- CLD
- XOR CH, CH
- MOV CL, Len {length in CX}
- MOV AX, CX {and in AX}
- STOSB {store length byte}
- MOV AL, C
- REP STOSB {fill string with char}
- end;
-
- function Pad(S : string; C : Char; Len : Byte) : string;
- begin
- IF length(S) < len then
- FillChar(S[succ(length(S))], Len-length(S), C);
- S[0] := char(Len);
- Pad := S;
- end;
-
- function APad(S: string; C: Char; Len: Byte): string; Assembler;
- ASM
- PUSH DS
- LDS SI, S {DS:SI points to S}
- LES DI, @Result {ES:DI points to result}
- LODSB {read existing length}
- XOR AH, AH
- MOV CX, AX
- MOV AL, Len {Set result to desired length}
- STOSB {Transfer length to result}
- MOV BX, CX
- REP MOVSB {Now S is in @Result}
- XOR CH, CH
- MOV CL, Len {Get desired length in CX}
- SUB CX, BX {Subtract current length}
- JLE @NoPad {If difference < 0, no pad}
- MOV AL, C {Put char in AL}
- REP STOSB {Fill rest of string}
- @NoPad:
- POP DS
- end;
-
- function LeftPad(S: string; C: Char; Len: Byte): string;
- begin
- IF length(S) < Len then
- begin
- MOVE(S[1], S[succ(Len - length(S))], length(S));
- FillChar(S[1], Len - length(S), C);
- end;
- S[0] := Char(Len);
- LeftPad := S;
- end;
-
- function ALeftPad(S: string; C: Char; Len: Byte): string; Assembler;
- ASM
- PUSH DS
- CLD
- LES DI, @Result {ES:DI points to result}
- MOV AL, Len
- XOR AH, AH
- MOV CX, AX {Desired length in CX}
- STOSB {length byte of result}
- LDS SI, S {DS:SI points to S}
- LODSB {AL has length of S}
- MOV BL, AL {remember length of S}
- SUB CX, AX {subtract actual from desired}
- JLE @NoPad {if diff < 0, don't pad}
- MOV AL, C {fill at start of string}
- REP STOSB
- @NoPad:
- MOV CL, BL {get back length of S}
- REP MOVSB {copy rest of S}
- POP DS
- end;
-
- function Chop(S: string; len: Byte): string;
- begin
- if length(S) > len then
- S[0] := Char(Len);
- Chop := S;
- end;
-
- procedure RChop(var S: string; len: Byte);
- begin
- if length(S) > len then
- S[0] := Char(Len);
- end;
-
- function AChop(S: string; len: Byte): string; Assembler;
- ASM
- PUSH DS
- LDS SI, S
- LES DI, @Result
- LODSB
- XOR AH, AH
- XCHG AX, CX
- CMP CL, Len {if length > len,...}
- JB @NoChop
- MOV CL, Len {... set length to len}
- @NoCHop:
- MOV AL, CL {store length}
- STOSB
- REP MOVSB {copy Len chars to result}
- POP DS
- end;
-
- function LeftChop(S: string; len: Byte): string;
- begin
- if length(S) > len then
- begin
- MOVE(S[succ(length(S) - len)],
- S[1], Len);
- S[0] := Char(Len);
- end;
- LeftChop := S;
- end;
-
- function LeftChopBy(S: string; len: Byte): string;
- begin
- IF length(S) > len then
- begin
- MOVE(S[succ(len)],
- S[1], Length(S)-Len);
- S[0] := Char(Length(S)-Len);
- end else S[0] := #0;
- LeftChopBy := S;
- end;
-
- procedure LChop(var S : string; len: Byte);
- begin
- IF length(S) > len then
- begin
- MOVE(S[succ(length(S) - len)],
- S[1], Len);
- S[0] := Char(Len);
- end;
- end;
-
- procedure LChopBy(var S : string; len: Byte);
- begin
- IF length(S) > len then
- begin
- MOVE(S[succ(len)], S[1], Length(S)-len);
- S[0] := Char(Length(S)-len);
- end;
- end;
-
- function ALeftChop(S: string; len: Byte): string; Assembler;
- ASM
- PUSH DS
- LDS SI, S
- LES DI, @Result
- LODSB
- XOR AH, AH
- XCHG AX, CX
- CMP CL, Len {if length > len,...}
- JB @NoChop
- ADD SI, CX {point to end of string}
- MOV CL, Len {set length to len}
- SUB SI, CX {point to new start of string}
- @NoCHop:
- MOV AL, CL {store length}
- STOSB
- REP MOVSB {copy Len chars to result}
- POP DS
- end;
-
- procedure Trim(var S : string; C : Char);
- begin
- while S[length(S)] = C do Dec(S[0]);
- end;
-
- procedure TrimTo(var S : string; C : Char);
- begin
- if Pos(C, S) <> 0 then LeftChop(S, Pos(C, S));
- end;
-
- procedure TrimLead(var S : string; C : Char);
- var P : Byte;
- begin
- P := 1;
- while (S[P] = C) and (P <= length(S)) do Inc(P);
- case P of
- 0 : S[0] := #0; {string was 255 of C!}
- 1 : ; {not found}
- else
- Move(S[P], S[1], succ(length(S) - P));
- Dec(S[0], pred(P));
- end;
- end;
-
- function LRTrim(S: string): string; assembler;
- asm
- mov bx, ds { save data segment }
- push es
- lds si, S { load source register with S }
- les di, @result { load destination register }
- mov cl, ds:[si] { move length of S into cx }
- or cl, cl { is it a zero? }
- jz @AssignNullString
- xor ch, ch { we only want the low byte }
- mov al, ' ' { store space in AL }
- @IsSpace:
- inc si
- cmp ds:[si], al
- loope @IsSpace { keep looping until it's not a blank }
- or cl, cl
- jnz @NotBlankString
- cmp ds:[si], al { last character could be a non-blank }
- je @AssignNullString
- @NotBlankString:
- inc cl
- inc di
- mov dl, cl { store CL in DL }
- cld { we are moving forward }
- repnz movsb { add string S to trimmed string }
- dec di
- mov cl, dl
- std
- repe scasb { while = to blank space }
- inc cl
- les di, @result { load destination register }
- @AssignNullString:
- mov es:[di], cl { move new length to trimmed string }
- pop es
- mov ds, bx { restore }
- end ;
-
- function NumLong(L: LongInt): string;
- var
- temp: string;
- begin
- Str(L, temp);
- NumLong := temp;
- end;
-
- function StrToReal(var code: integer; S: string): real;
- var
- V: real;
- {code: integer;}
- begin
- Val(S, V, code);
- StrToReal := V;
- end;
-
- function RealToStr(R: real; NumDec: byte): string;
- var
- temp: string;
- begin
- Str(R:0:NumDec, temp);
- RealToStr := temp;
- end;
-
- procedure Replace(NewString, OldString: string; var MainString: string);
- begin
- Insert(NewString, MainString, Pos(OldString, MainString));
- Delete(MainString, Pos(OldString, MainString), Length(OldString));
- end;
-
- procedure InsertAfter(NewString, AnchorString: string;
- var MainString: string; Spacer: byte);
- begin
- Insert(NewString, MainString, Pos(AnchorString, MainString)+Spacer);
- Delete(MainString, Pos(AnchorString, MainString)+Length(NewString)+Spacer, Length(NewString));
- end;
-
- {*
- * Name : CopyInto
- * Purpose : Copy InStr into OutStr at column Col.
- * Parameters : InStr - the string to be inserted
- * Col - where to insert
- * OutStr- the string to insert into, and result
- * Notes : This routine is great for for creating formated output.
- * This is not just another INSERT. It does not move any chars
- * like insert, it just overwrites the existing string. Will
- * not copy beyond the end of the Destination string.
- * Basically, you just make a string of all blanks the desired
- * length, then copy other strings into it at fixed columns.
- *}
- Procedure CopyInto(const InStr: string; Column: Byte; var OutStr: string);
- begin
- if (Byte(InStr[0]) <> 0) then
- begin
- if (Column > Byte(OutStr[0])) then
- Exit
- else if (Column + Byte(InStr[0]) - 1 > Byte(OutStr[0])) then
- Move(InStr[1], OutStr[Column], Byte(OutStr[0]) - Column + 1)
- else
- Move(InStr[1], OutStr[Column], Byte(InStr[0]));
- end;
- end;
-
- function FCopyInto(const InStr: string; Column: Byte; OutStr: string): string;
- begin
- CopyInto(InStr, Column, OutStr);
- FCopyInto := OutStr;
- end;
-
- function SubStr(S: string; BegChar, EndChar: char): string;
- begin
- SubStr := Copy(S, Pos(BegChar, S), Pos(EndChar, S)-Pos(BegChar, S)+1);
- end;
-
- function JustifyStr(var S: string; L: byte; Just: Justification): string;
- var
- i: integer;
- begin
- if Length(S) > L then byte(S[0]) := L;
- case Just of
- jLeft: S := Pad(S, ' ', L);
- jRight: S := LeftPad(S, ' ', L);
- jCenter: S := LeftPad(S, ' ', (L div 2)-(Length(S) div 2));
- end;
- JustifyStr := S;
- end;
-
- function StrToMask(S: string; Mask: string): string;
- var
- i: integer;
- Negative: boolean;
- begin
- S := LRTrim (S);
- Negative := S[1] = '-';
- if Negative then
- S := copy(S, 2, length(S));
-
- { add commas }
- if pos(',', Mask) <> 0 then
- begin
- { calc first comma pos }
- i := pos('.', S );
- if i = 0 then
- i := length(S) - 2
- else
- dec(i, 3);
- while i > 1 do
- begin
- Insert(',', S, i);
- dec (i, 3);
- end;
- end;
-
- { add a dollar sign }
- if pos ('$', Mask) <> 0 then
- S := '$' + S;
-
- { add a percent sign }
- if pos ('%', Mask) <> 0 then
- S := S + '%';
-
- { add a minus sign }
- if Negative then
- S := '-' + S;
-
- StrToMask := LeftPad(S, ' ',length(Mask));
- end;
-
- function StripMask (S: string ): string;
- const
- ValidChars = ['0'..'9', '.', '-'];
- var
- St: string;
- i: integer;
- begin
- St := '';
- for i := 1 to length (S) do
- if S[i] in ValidChars then
- St := St + S [i];
- StripMask := St;
- end;
-
- procedure CutFirstDirectory(var S: TFileName);
- var
- Root: Boolean;
- P: Integer;
- begin
- if S = '\' then S := ''
- else begin
- if S[1] = '\' then
- begin
- Root := True;
- S := Copy(S, 2, 255);
- end else Root := False;
- if S[1] = '.' then S := Copy(S, 5, 255);
- P := Pos('\',S);
- if P <> 0 then S := '...\' + Copy(S, P + 1, 255)
- else S := '';
- if Root then S := '\' + S;
- end;
- end;
-
- function MinimizeName(const Filename: TFileName; Canvas: TCanvas;
- MaxLen: Integer): TFileName;
- var
- Drive: string[3];
- Dir: TFileName;
- Name: TFileName;
- Ext: TFileName;
- P: Integer;
- begin
- Result := FileName;
- Dir := ExtractFilePath(Result);
- Name := ExtractFileName(Result);
- P := Pos('.', Name);
- if P > 0 then Name[0] := Chr(P - 1);
- Ext := ExtractFileExt(Result);
-
- if Dir[2] = ':' then
- begin
- Drive := Copy(Dir, 1, 2);
- Dir := Copy(Dir, 3, 255);
- end else Drive := '';
- while ((Dir <> '') or (Drive <> '')) and (Canvas.TextWidth(Result) > MaxLen) do
- begin
- if Dir = '\...\' then
- begin
- Drive := '';
- Dir := '...\';
- end else if Dir = '' then Drive := ''
- else CutFirstDirectory(Dir);
- Result := Drive + Dir + Name + Ext;
- end;
- end;
-
- end.